import type { IntervalTaskProps } from '../../timer_manager'
import QuickLRU from 'quick-lru'
import { logger, TIME_UNITS } from '../../../types/constants'
import { SYMBOLS } from '../../../types/interfaces'
import { TimerManager } from '../../timer_manager'

/**
 * 支持的哈希算法类型
 */
export enum HashAlgorithm {
  SHA_1 = 'SHA-1',
  SHA_256 = 'SHA-256',
  SHA_384 = 'SHA-384',
  SHA_512 = 'SHA-512',
}

/**
 * 哈希输出格式
 */
export enum HashOutputFormat {
  HEX = 'hex',
  BASE64 = 'base64',
}

/**
 * 元素 ID 生成配置选项
 */
export interface ElementIdOptions {
  /** 输出格式 */
  outputFormat?: HashOutputFormat
  /** ID 前缀 */
  prefix?: string
  /** ID 后缀 */
  suffix?: string
  /** ID 最大长度（0表示不限制） */
  maxLength?: number
  /** 是否使用短哈希（取前8位） */
  useShortHash?: boolean
  /** 自定义 ID 格式化函数 */
  formatter?: (hash: string, content: string) => string
  /** 是否包含内容长度信息 */
  includeLength?: boolean
  /** 是否使用缓存 */
  useCache?: boolean
}

/**
 * 哈希计算配置选项
 */
export interface HashComputeOptions {
  /** 输出格式 */
  outputFormat?: HashOutputFormat
  /** 是否启用降级处理（针对不支持的算法） */
  enableFallback?: boolean
  /** 自定义降级处理函数 */
  fallbackHandler?: (content: string, format: HashOutputFormat) => Promise<string>
  /** 是否使用缓存 */
  useCache?: boolean
  /** 缓存过期时间（毫秒） */
  cacheTTL?: number
}

/**
 * 缓存项信息接口
 */
interface CachedHashInfo {
  value: string
  timestamp: number
  ttl: number
  algorithm: HashAlgorithm
  outputFormat: HashOutputFormat
}

/**
 * 缓存统计信息
 */
interface CacheStats {
  hits: number
  misses: number
  size: number
  hitRate: number
  evictions: number
  lastCleanup: number
}

/**
 * 便捷哈希函数类型定义
 */
export interface HashFunction {
  (content: string): Promise<string>
  (content: string, outputFormat: HashOutputFormat): Promise<string>
  (content: string, outputFormat: HashOutputFormat, options: Omit<HashComputeOptions, 'outputFormat'>): Promise<string>
}

/**
 * 元素 ID 生成函数类型定义
 */
export interface ElementIdFunction {
  (content: string): Promise<string>
  (content: string, options: ElementIdOptions): Promise<string>
}

/**
 * 加密工具类
 * TODO: 使用内存存储缓存，未使用本地存储
 */
export class CryptoUtils {
  private readonly name: string = 'CryptoUtils'
  private static instance: CryptoUtils
  private timerManager: TimerManager = TimerManager.getInstance()
  private readonly encoder = new TextEncoder()
  private readonly intervalTask: IntervalTaskProps = {
    id: 'cleanup-expired-hash-cache',
    interval: TIME_UNITS.COMMON.INTERVALS.ONE_MINUTE,
    running: false,
  }

  private readonly maxHashCache: number = 1000 // 最大缓存数量
  private hashCache: QuickLRU<string, CachedHashInfo> = new QuickLRU<string, CachedHashInfo>({
    maxSize: this.maxHashCache,
  })

  private defaultCacheTTL: number = TIME_UNITS.COMMON.INTERVALS.FIVE_MINUTES
  private defaultCacheStats: CacheStats = {
    hits: 0,
    misses: 0,
    size: 0,
    hitRate: 0,
    evictions: 0,
    lastCleanup: 0,
  }

  private cacheStats: CacheStats = {
    ...this.defaultCacheStats,
  }

  private constructor() {
    this.initializeCacheCleanup()
  }

  /**
   * 获取单例实例
   */
  static getInstance(): CryptoUtils {
    if (!CryptoUtils.instance) {
      CryptoUtils.instance = new CryptoUtils()
    }
    return CryptoUtils.instance
  }

  /**
   * 销毁实例
   */
  destroy(): void {
    if (this.intervalTask.running) {
      this.timerManager.clearInterval(this.intervalTask.id)
      this.intervalTask.running = false
    }
    this.clearCache()
  }

  /**
   * 初始化缓存清理定时器
   */
  private initializeCacheCleanup(): void {
    this.timerManager.createTimerTask({
      id: this.intervalTask.id,
      interval: this.intervalTask.interval,
      callback: () => {
        this.cleanupExpiredCache()
      },
    })

    this.intervalTask.running = true
  }

  /**
   * 生成缓存键
   */
  private generateCacheKey(
    content: string,
    algorithm: HashAlgorithm,
    outputFormat: HashOutputFormat,
  ): string {
    return `${algorithm}:${outputFormat}:${content}`
  }

  /**
   * 获取缓存值
   */
  getCacheValue(content: string, algorithm: HashAlgorithm, outputFormat: HashOutputFormat): string | null {
    const cacheKey = this.generateCacheKey(content, algorithm, outputFormat)
    return this.getFromCache(cacheKey)
  }

  /**
   * 从缓存中获取值
   */
  private getFromCache(cacheKey: string): string | null {
    const item = this.hashCache.get(cacheKey)

    if (!item) {
      this.cacheStats.misses++
      this.updateHitRate()
      return null
    }

    // 检查是否过期
    if (Date.now() - item.timestamp > item.ttl) {
      this.hashCache.delete(cacheKey)
      this.cacheStats.misses++
      this.updateHitRate()
      return null
    }

    this.cacheStats.hits++
    this.updateHitRate()
    logger.debug(`[${this.name}] 缓存命中: ${cacheKey.substring(0, 50)}...`)
    return item.value
  }

  /**
   * 设置缓存值
   */
  private setToCache(
    cacheKey: string,
    value: string,
    algorithm: HashAlgorithm,
    outputFormat: HashOutputFormat,
    ttl: number,
  ): void {
    const cacheItem: CachedHashInfo = {
      value,
      timestamp: Date.now(),
      ttl: ttl || this.defaultCacheTTL,
      algorithm,
      outputFormat,
    }

    this.hashCache.set(cacheKey, cacheItem)
    this.cacheStats.size = this.hashCache.size
    logger.debug(`[${this.name}] 缓存设置: ${cacheKey.substring(0, 50)}... (TTL: ${ttl}ms)`)
  }

  /**
   * 清理过期缓存
   */
  private cleanupExpiredCache(): void {
    const now = Date.now()
    let cleanedCount = 0

    for (const [key, item] of this.hashCache.entries()) {
      if (now - item.timestamp > item.ttl) {
        this.hashCache.delete(key)
        cleanedCount++
      }
    }

    this.cacheStats.size = this.hashCache.size
    this.cacheStats.lastCleanup = now

    if (cleanedCount > 0) {
      logger.debug(`[${this.name}] ${SYMBOLS.UI.TRASH} 清理了 ${cleanedCount} 个过期缓存项`)
    }
  }

  /**
   * 更新缓存命中率
   */
  private updateHitRate(): void {
    const total = this.cacheStats.hits + this.cacheStats.misses
    this.cacheStats.hitRate = total > 0 ? this.cacheStats.hits / total : 0
  }

  /**
   * 获取缓存统计信息
   */
  getCacheStats(): CacheStats {
    return { ...this.cacheStats }
  }

  /**
   * 清空缓存
   */
  clearCache(): void {
    const size = this.hashCache.size
    this.hashCache.clear()
    this.cacheStats = { ...this.defaultCacheStats }
    logger.info(`[${this.name}] ${SYMBOLS.UI.TRASH} 清空缓存，移除了 ${size} 个缓存项`)
  }

  /**
   * 计算哈希值
   */
  async computeHash(
    content: string,
    algorithm: HashAlgorithm,
    options: HashComputeOptions = {},
  ): Promise<string> {
    const {
      outputFormat = HashOutputFormat.HEX,
      enableFallback = false,
      fallbackHandler,
      useCache = false,
      cacheTTL = this.defaultCacheTTL,
    } = options

    this.validateCryptoSupport()

    // 尝试从缓存中获取值
    if (useCache) {
      const cached = this.getCacheValue(content, algorithm, outputFormat)
      if (cached !== null) {
        return cached
      }
    }

    logger.debug(`${SYMBOLS.NETWORK.LOCK_WITH_KEY} 开始计算 ${algorithm} 哈希值...`)

    try {
      const data = this.encoder.encode(content)
      const hashBuffer = await crypto.subtle.digest(algorithm, data)
      const result = this.formatHashOutput(hashBuffer, outputFormat, algorithm)

      // 存入缓存
      if (useCache) {
        const cacheKey = this.generateCacheKey(content, algorithm, outputFormat)
        this.setToCache(cacheKey, result, algorithm, outputFormat, cacheTTL)
      }

      return result
    }
    catch (error) {
      // 处理降级逻辑
      if (enableFallback) {
        logger.warn(`不支持 ${algorithm} 算法`, error)
        return this.handleAlgorithmFallback(content, algorithm, outputFormat, fallbackHandler)
      }
      else {
        logger.warn(`不支持 ${algorithm} 算法， 返回空字符串`, error)
      }

      return ''
    }
  }

  /**
   * 批量计算哈希值
   */
  async batchComputeHash(
    contents: string[],
    algorithm: HashAlgorithm,
    options: HashComputeOptions = {},
  ): Promise<string[]> {
    logger.debug(`${SYMBOLS.NETWORK.LOCK_WITH_KEY} 批量计算 ${contents.length} 个内容的 ${algorithm} 哈希...`)

    const results: string[] = []
    const toCompute: { index: number, content: string }[] = []

    // 先检查缓存
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i]
      const cacheKey = this.generateCacheKey(content, algorithm, options.outputFormat || HashOutputFormat.HEX)
      const cached = options.useCache ? this.getFromCache(cacheKey) : null

      if (cached !== null) {
        results[i] = cached
      }
      else {
        toCompute.push({ index: i, content })
      }
    }

    // 并行计算未缓存的项
    if (toCompute.length > 0) {
      const computePromises = toCompute.map(({ index, content }) =>
        this.computeHash(content, algorithm, options).then(hash => ({ index, hash })),
      )

      const computedResults = await Promise.all(computePromises)

      for (const { index, hash } of computedResults) {
        results[index] = hash
      }
    }

    logger.debug(`${SYMBOLS.STATUS.SUCCESS} 批量计算完成: 缓存命中 ${contents.length - toCompute.length} 个, 实际计算 ${toCompute.length} 个`)

    return results
  }

  /**
   * 算法降级处理
   */
  private async handleAlgorithmFallback(
    content: string,
    algorithm: HashAlgorithm,
    outputFormat: HashOutputFormat,
    customFallback?: (content: string, format: HashOutputFormat) => Promise<string>,
  ): Promise<string> {
    logger.warn(`使用降级方案处理 ${algorithm} 算法`)

    if (customFallback) {
      logger.debug(`${SYMBOLS.STATUS.INFO} 使用自定义降级处理器`)
      return customFallback(content, outputFormat)
    }

    // 内置降级处理
    switch (algorithm) {
      default:
        throw new Error(`${SYMBOLS.STATUS.ERROR} 不支持的算法: ${algorithm}`)
    }
  }

  /**
   * 根据内容生成元素 ID（使用 SHA-256） -自动过滤不适合作为 ID 的字符和内容
   */
  async generateElementId(
    content: string,
    options: ElementIdOptions = {},
  ): Promise<string> {
    const {
      outputFormat = HashOutputFormat.HEX,
      prefix = '',
      suffix = '',
      maxLength = 0,
      useShortHash = true,
      formatter,
      includeLength = false,
      useCache = false,
    } = options
    // 1. 计算 SHA-256 哈希
    const fullHash = await this.computeHash(content, HashAlgorithm.SHA_256, {
      outputFormat,
      useCache,
    })

    // 2. 处理哈希结果
    let finalHash = this.elementIdFormatter(fullHash)

    if (useShortHash) {
      // 取前 8 位作为短哈希（类似 Git 的commit hash）
      finalHash = fullHash.substring(0, 8)
    }

    // 3. 应用长度限制
    if (maxLength > 0 && finalHash.length > maxLength) {
      finalHash = finalHash.substring(0, maxLength)
    }

    // 4. 构建最终 ID
    let elementId: string

    if (formatter) {
      // 使用自定义格式化函数
      elementId = formatter(finalHash, content)
    }
    else {
      // 默认格式化
      const parts: string[] = []

      if (prefix)
        parts.push(prefix)
      parts.push(finalHash)
      if (includeLength)
        parts.push(`len${content.length}`)
      if (suffix)
        parts.push(suffix)

      elementId = parts.join('-')
    }

    logger.debug(`${SYMBOLS.UI.BOOKMARK} 为内容生成元素 ID: ${elementId} (原内容长度: ${content.length})`)
    return elementId
  }

  /**
   * 元素 ID 格式化函数
   */
  elementIdFormatter(hash: string): string {
    // 必须以字母开头，只包含字母、数字、连字符
    const cssFriendlyHash = hash.replace(/[^a-z0-9-]/gi, '-')
    // 确保以字母开头
    return cssFriendlyHash.match(/^[a-z]/i) ? cssFriendlyHash : `id-${cssFriendlyHash}`
  }

  /**
   * 格式化哈希输出
   *
   * @param hashBuffer - 原始哈希缓冲区
   * @param outputFormat - 输出格式
   * @param algorithm - 算法类型（用于日志）
   * @returns 格式化后的哈希字符串
   *
   * @private
   */
  private formatHashOutput(
    hashBuffer: ArrayBuffer,
    outputFormat: HashOutputFormat,
    algorithm: string,
  ): string {
    const hashArray = Array.from(new Uint8Array(hashBuffer))

    let result: string

    if (outputFormat === HashOutputFormat.BASE64) {
      // 转换为 Base64
      const binaryString = String.fromCharCode(...hashArray)
      result = btoa(binaryString)
    }
    else {
      // 转换为十六进制格式
      result = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
    }

    logger.debug(`${SYMBOLS.STATUS.SUCCESS} '${algorithm}' 哈希计算完成: ${result.substring(0, 16)}...`)
    return result
  }

  /**
   * 验证浏览器加密支持
   */
  private validateCryptoSupport(): void {
    if (!crypto || !crypto.subtle)
      throw new Error(`${SYMBOLS.STATUS.ERROR} 浏览器不支持 Web Crypto API，无法进行加密计算`)

    logger.debug(`${SYMBOLS.STATUS.SUCCESS} Web Crypto API 支持验证通过`)
  }
}

/**
 * 便捷函数工厂：创建特定算法的便捷计算函数
 * 使用函数重载和类型推断，避免冗长的类型声明
 */
function createHashFunction<T extends HashAlgorithm>(algorithm: T): HashFunction {
  return (
    content: string,
    outputFormat?: HashOutputFormat,
    options?: Omit<HashComputeOptions, 'outputFormat'>,
  ): Promise<string> => {
    const finalOutputFormat = outputFormat || HashOutputFormat.BASE64
    const finalOptions: HashComputeOptions = {
      ...options,
      outputFormat: finalOutputFormat,
    }
    return CryptoUtils.getInstance().computeHash(content, algorithm, finalOptions)
  }
}

/**
 * 元素 ID 生成函数工厂
 */
function createElementIdFunction(options?: ElementIdOptions): ElementIdFunction {
  return async (
    content: string,
    idOptions?: ElementIdOptions,
  ): Promise<string> => {
    const finalOptions = { ...options, ...idOptions }
    return CryptoUtils.getInstance().generateElementId(content, finalOptions)
  }
}

/**
 * 导出便捷函数
 */
export const sha256: HashFunction = createHashFunction(HashAlgorithm.SHA_256)
// export const md5: HashFunction = createHashFunction(HashAlgorithm.MD5) // 不支持
export const sha1: HashFunction = createHashFunction(HashAlgorithm.SHA_1)
export const sha384: HashFunction = createHashFunction(HashAlgorithm.SHA_384)
export const sha512: HashFunction = createHashFunction(HashAlgorithm.SHA_512)
export const generateElementId: ElementIdFunction = createElementIdFunction()
